#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define swap(n) ( (n&0x00ff << 8) | (n&0xff00 >>8) )

typedef struct read_response_ {
  unsigned short msg_size;
  unsigned char command;
  unsigned char id;
  unsigned short index;
  unsigned char status;
  unsigned short data_size;

} read_response_t;
 
int handle_read(unsigned char *req, unsigned char *resp)
{
  req++;// skip command id

  unsigned char id = *req++;
  unsigned short file_index = *req <<8 | *(req+1);
  req++;req++;

  unsigned char *end = index(req,0);
  int filename_len = end - req;
  unsigned char *filename_p = req;
  unsigned char status = 0;// OK

  req += filename_len+1;

  unsigned short data_size =  *req <<8 | *req++;

  printf("id: %d, index: %d, file: %s (%d), size: %d\n",
      id,file_index,
      filename_p,filename_len,
      data_size
  );

  char filename[32+13];
  sprintf(filename,"/var/run/pds/%s",filename_p);

  if (! data_size ) {
    printf("stat file\n");

    return;
  }

  unsigned short msg_size = data_size +9;

  char *buf = malloc(data_size);
  *resp = buf;

  read_response_t *header = buf;

  header->msg_size = swap(msg_size);
  header->command  = 5;
  header->id = id;
  header->index = swap(file_index);
  header->status = status;// FIXME
  header->data_size = swap(data_size);

  buf += 9;// FIXME: constant


  // FIXME: structure
  // format write packet
  /*
  *buf++ = msg_size & 0x00ff; 
  *buf++ = (msg_size & 0xff00) >> 8;
  *buf++ = 5;
  *buf++ = id;
  *buf++ = file_index & 0x00ff;
  *buf++ = (file_index & 0xff00) >>8;
  *buf++ = status;
  *buf++ = data_size & 0x00ff; 
  *buf++ = (data_size & 0xff00) >> 8;
  */

  int fd = open(filename,O_RDONLY);

  if(fd < 0) {
    printf("cant open file\n");
    goto ret;
  }

  int nread = read(fd,buf,data_size);
  close(fd);

  if (nread != data_size) {
    printf("invalid read value: %d %d\n",nread, data_size);
    goto ret;
  }

  printf("buf: %x\n",*resp);

  return msg_size;

ret:
  printf("error.\n");
  *resp = NULL; 
  return 0;



}

int main() {
  int mux = open ("/dev/netmux/nvm_proxy",O_RDWR);

  if (mux < 0) {
    printf("cant open mux\n");
    return 1;
  }

  unsigned char req_len_raw[2];
  int req_len = 0;

  int readn = 0;

  fd_set dev;
  FD_ZERO(&dev);

  while (1)
  {
    // wait for message header
    FD_SET(mux,&dev);
    select(FD_SETSIZE,&dev,NULL,NULL,NULL);

    // read message length
    readn = read(mux,req_len_raw,2);
    
    // some shit happened
    if (readn != 2) {
      printf("invalid len read: %d\n",readn);
      continue;
    }

    // calculate left message length
    req_len = (req_len_raw[0]<<8 | req_len_raw[1] )-2;

    printf("reading next %d\n",req_len);

    // allocate buffer for known message len
    unsigned char *req = malloc(req_len);

    // wait for message
    FD_SET(mux,&dev);
    select(FD_SETSIZE,&dev,NULL,NULL,NULL);

    // read message
    readn = read(mux,req,req_len);

    // some shit happened
    if (readn != req_len) {
      printf("invalid req read: %d\n",readn);
      continue;
    }

    unsigned char *write_buf = NULL;
    unsigned short write_size = 0;

    int n;

    switch (*req) {
      case 1:
        printf("read request\n");
        for (n=0; n< readn; n++) {
          printf("%x:",req[n]);
        }
        printf("\n");

        write_size = handle_read(req,&write_buf);
        printf("write buffer: %x\n",write_buf);

        break;
      case 2:
        printf("write request\n");

        break;
      case 3:
        printf("delete request\n");

        break;

      case 4:
        printf("status request\n");

        break;

    } // case req

    // response not formed
    if(! write_buf ) {
      printf("no write buffer\n");
      continue;
    }

    // response not read correctly
    if(! write_size ) {
      printf("nothing to write\n");
      continue;
    }
    printf("response\n");

    for (n=0; n< write_size; n++) {
      printf("%x:",write_buf[n]);
    }
    printf("\n");   

  }   // while 1
}
